﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Net.Sockets;
using System.Threading;
using WPFExcelReport.Helpers;
namespace WPFExcelReport
{

    /// <summary>
    /// 与客户端的 连接通信类(包含了一个 与客户端 通信的 套接字，和线程)
    /// </summary>
    public class AMClient
    {
        ApplicationBase app
        {
            get
            {
                return ApplicationBase.Instance;
            }
        }
        int fails = 0;
        public Dictionary<string, object> ENVMAIN
        {
            get
            {
                return app.ENVMAIN(app.ServiceUri);
            }
        }
        public Dictionary<string, object> SVRENVMAIN
        {
            get
            {
                return app.ENVMAIN(app.ServiceUri);
            }
        }
        public AMServer VSP
        {
            get
            {
                if (!SVRENVMAIN.ContainsKey("VSP"))
                    return null;
                return (AMServer)SVRENVMAIN["VSP"];
            }
        }
        public VICC_ZLAN VZL
        {
            get
            {
                if (!ENVMAIN.ContainsKey("VZL"))
                    return null;
                return (VICC_ZLAN)ENVMAIN["VZL"];
            }
        }
        public ZLANServer VSK
        {
            get
            {
                if (!ENVMAIN.ContainsKey("VSK"))
                    return null;
                return (ZLANServer)ENVMAIN["VSK"];
            }
        }
        public DataTable TBZLAM
        {
            get;
            set;
        }
        private string _MACHINEID = "";
        public string MACHINEID
        {
            get
            {
                return _MACHINEID;
            }
            set
            {
                _MACHINEID = value;
            }
        }
        public Socket SocketClient;
        public string EndPoint
        {
            get;
            set;
        }
        public string PLCIP
        {
            get;
            set;
        }
        bool _IsPortReaday = false;
        public bool IsPortReaday
        {
            get
            {
                return _IsPortReaday;
            }
            set
            {
                _IsPortReaday = value;
            }
        }
        public Thread receiveThread;
        public Thread SimulationThread;
        /// <summary>
        /// 定时到数据库中读取数据，跟本台设备有关的信息
        /// 若是设备传感器有联通，则直接连设备传感器
        /// 维护一个订阅列表
        /// 客户端加入后，根据自己的端口号，发送注册信息到服务器，服务器处理
        /// </summary>
        /// <param name="clientSocket"></param>
        public AMClient(Socket clientSocket)
        {
            this.SocketClient = clientSocket;
            EndPoint = clientSocket.RemoteEndPoint.ToString();
            int idx = EndPoint.IndexOf(':');
            PLCIP = EndPoint.Substring(0, idx);
            receiveThread = new Thread(ReceiveMessage);
            receiveThread.Name = Guid.NewGuid().ToString();
            receiveThread.IsBackground = true;
            receiveThread.Start();
        }
        public Dictionary<string, string> SubscribedValue = new Dictionary<string, string>();

        public void CNTAUTOLISTEN()
        {
            try
            {
                if (MACHINEID.Length < 8)
                    return;
                DataSet SResult = VZL.CNTAUTOLISTEN(MACHINEID.Substring(0, 8));
                DataTable TBAM06 = SResult.Tables[0].Copy();
                foreach (DataRow row in TBAM06.Rows)
                {
                    //谁订阅了哪些值
                    string BDEKEN = row["AMEBDEKEN"].ToString().Trim();
                    SubscribedValue[EndPoint + ":" + MACHINEID + ":" + row["BDEKEY"].ToString()] = BDEKEN.Trim();
                }
            }
            catch (Exception ex)
            {
                Helpers.LogHelper.error(ex.Message);
            }
        }
       
        
        public void CNTAUTOSTOP()
        {
            try
            {
                if (MACHINEID.Length < 8)
                    return;
                var Subscribers = from client in SubscribedValue
                                  where client.Key.Contains(":" + MACHINEID + ":")
                                  select client;
                foreach (KeyValuePair<string, string> kp in Subscribers)
                {
                    //谁订阅了哪些值
                    SubscribedValue.Remove(kp.Key);
                }
            }
            catch (Exception ex)
            {
                Helpers.LogHelper.error(ex.Message);
            }
        }
        bool isRec = true;
        #region 02负责监听客户端发送来的消息 
        private void ReceiveMessage()
        {
            byte[] received = new byte[1024];
            while (true)
            {
                try
                {

                    //通过clientSocket接收数据  
                    int length = SocketClient.Receive(received);
                    if (length < 1)
                        break;
                    if (!SocketClient.Connected)
                        break;
                    byte[] data = new byte[length];
                    for (int i = 0; i < length; i++)
                    {
                        data[i] = received[i];
                    }
                    string strMsg = System.Text.Encoding.ASCII.GetString(received, 0, length);

                    //Helpers.LogHelper.info("Subscriber:" + strMsg);
                    string[] msg = strMsg.Split(':');
                    if (msg.Length == 0)
                        continue;
                    switch (msg[0])
                    {
                        //找到该机台的所有监控点，并和ZLAN关联
                        case "REG":
                            MACHINEID = msg[1];
                            CNTAUTOLISTEN();//产生订阅
                            break;
                        case "SIMULATE":
                            LogHelper.info("Simulation Start");
                            SimulationThread = new Thread(SIMULATE);
                            SimulationThread.Name = Guid.NewGuid().ToString();
                            SimulationThread.IsBackground = true;
                            SimulationThread.Start(); 
                            break;
                        case "UNREG":
                            MACHINEID = msg[1];
                            CNTAUTOSTOP();//产生订阅
                            break;
                        default:
                            break;
                    }
                }
                catch (Exception ex)
                {
                    fails++;
                    if (fails > 10)
                        CloseConnection();
                    LogHelper.error(ex.Message);
                }
            }
        }
        #endregion

        #region 03向客户端发送消息
        int failsconnection = 0;
        /// <summary>
        /// 向客户端发送消息
        /// </summary>
        /// <param name="strMsg"></param>
        public void Send(string command, string DataSend,long time)
        {
            if (!SocketClient.Connected)
            {
                failsconnection++;
                if (failsconnection > 1000)
                {
                    SubscribedValue.Clear();
                    CloseConnection();
                }
                return;
            }
            if (lastticks > time)
                return;
            lastticks = time;//不发送滞后的时间戳任务
            string sendMessage = command + ":" + DataSend + ";" + time + ",";
            byte[] bytes = System.Text.Encoding.ASCII.GetBytes(sendMessage);
            SocketClient.Send(bytes);
        }
        
        long lastticks = -1;
        long ticks = -1;
        string date = "", time = "";
        public void SIMULATE()
        {
            int i = 0;
            while (true)
            { 
                i = i + 1;
                Helper.GetTime(ref date, ref time,ref ticks);
                try
                {
                    var Subscribers = from client in VSP.Clients
                                      select client;
                    foreach (KeyValuePair<string, AMClient> client in Subscribers)
                    {
                        foreach (KeyValuePair<string, string> kp in client.Value.SubscribedValue)
                        {
                            client.Value.Send(kp.Value, i.ToString(), ticks);
                        }
                    }
                }
                catch(Exception ex)
                {
                   
                }
                if (i > 1000)
                    i = 0;
                
                Thread.Sleep(1000);
            }
        }
        #endregion
        #region 06关闭与客户端连接
        /// <summary>
        /// 关闭与客户端连接
        /// </summary>
        public void CloseConnection()
        {
            try
            {
                receiveThread.Abort();
                isRec = false;
                if (SocketClient.Connected)
                {
                    SocketClient.Shutdown(SocketShutdown.Both);
                }
                SocketClient.Close();
            }
            catch (Exception ex)
            {
                LogHelper.error(ex.Message);
            }

        }
        #endregion
    }
}
